package javaframework;

import framework.Color;
import framework.ImageTinter;
import framework.ImageWrapper;
import framework.Rectangle;

import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.RescaleOp;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;

import framework.GraphicsWrapper;

public class JavaGraphics implements GraphicsWrapper {

	private Graphics2D my_graphics;
	private List<AffineTransform> my_matrixStack;
	private int my_width;
	private int my_height;
	
	public JavaGraphics() {
		my_matrixStack = new ArrayList<AffineTransform>();
	}
	public JavaGraphics(final int the_width, final int the_height) {
		my_width = the_width;
		my_height = the_height;
		my_matrixStack = new ArrayList<AffineTransform>();
	}
	
	public void setGraphics(final Graphics2D the_graphics) {
		my_matrixStack.clear();
		my_graphics = the_graphics;
	}
	public void resize(final int the_width, final int the_height) {
		my_width = the_width;
		my_height = the_height;
	}
	
	@Override
	public int getWidth() {
		return my_width;
	}

	@Override
	public int getHeight() {
		return my_height;
	}

	@Override
	public void setColor(Color the_color) {
		my_graphics.setColor(new java.awt.Color(the_color.getRed(),
				the_color.getGreen(), the_color.getBlue(),
				the_color.getAlpha()));
	}

	@Override
	public void fillRect(int the_x, int the_y, int the_width, int the_height) {
		my_graphics.fillRect(the_x, the_y, the_width, the_height);
		
	}
	
	@Override
	public void fillOval(int the_x, int the_y, int the_width, int the_height) {
		my_graphics.fillOval(the_x, the_y, the_width, the_height);
		
	}
	
	@Override
	public Rectangle getStringBounds(String the_string) {
		Rectangle2D rect = my_graphics.getFontMetrics().getStringBounds(the_string, my_graphics);
		return new Rectangle(rect.getWidth(), rect.getHeight());
	}
	
	@Override
	public void drawString(final String the_string, final int the_x, final int the_y) {
		my_graphics.drawString(the_string, the_x, the_y);
	}
	
	@Override
	public ImageWrapper newImage(final int the_width, final int the_height) {
		return new JavaImage(the_width, the_height);
	}
	@Override
	public void drawImage(final ImageWrapper the_image, final int the_x, final int the_y) {
		my_graphics.drawImage(((JavaImage) the_image).getBufferedImage(), the_x, the_y, the_image.getWidth(), the_image.getHeight(), null);
	}
	@Override
	public ImageTinter newImageTinter(final Color the_color) {
		System.out.println("new tinter");
		return new JavaImageTinter(the_color);
	}

	@Override
	public void translate(double the_x, double the_y) {
		my_graphics.translate(the_x, the_y);
	}

	@Override
	public void scale(double the_x, double the_y) {
		my_graphics.scale(the_x, the_y);		
	}
	@Override
	public void saveMatrix() {
		my_matrixStack.add(my_graphics.getTransform());
		
	}
	@Override
	public void restoreMatrix() {
		if (my_matrixStack.isEmpty()) {
			throw new NoSuchElementException("No matrix to restore");
		}
		my_graphics.setTransform(my_matrixStack.remove(my_matrixStack.size() - 1));
	}
	@Override
	public void dispose() {
		my_graphics.dispose();
	}

	@Override
	public void clear() {
		// from http://stackoverflow.com/questions/2367365/clear-a-transparent-bufferedimage-as-fast-as-possible
		final Composite composite = my_graphics.getComposite();
		my_graphics.setComposite(AlphaComposite.Clear);
		my_graphics.fillRect(0, 0, my_width, my_height);
		my_graphics.setComposite(composite);
	}
	public class JavaImageTinter implements ImageTinter {
		private final RescaleOp my_op;
		public JavaImageTinter(final Color the_color) {
			float[] scales = {the_color.getRed() / 255f,
					the_color.getGreen() / 255f, the_color.getBlue() / 255f,
					1};
			float[] offsets = new float[4];
			my_op = new RescaleOp(scales, offsets, null);
		}

		@Override
		public void drawTintedImage(final GraphicsWrapper the_graphics, ImageWrapper the_image, int the_x, int the_y) {
			((JavaGraphics) the_graphics).my_graphics.drawImage(((JavaImage)the_image).getBufferedImage(), my_op, the_x, the_y);
			
		}
		
	}

}
